package com.gqb.spring.framework;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.ObjectUtils.Null;
import org.xml.sax.SAXException;

import com.gqb.annotation.Component;
import com.gqb.annotation.Resource;
import com.gqb.annotation.Value;
import com.gqb.spring.bean.BeanUtil;
import com.gqb.spring.bean.StringUtil;
import com.gqb.spring.tag.Beans;
import com.gqb.spring.tag.Scan;

public class AnnotationBeanFactory extends AbstractBeanFactory  {
	private AbstractBeanFactory parentFactory;
	
	public AnnotationBeanFactory(AbstractBeanFactory abstractBeanFactory) {
		this.parentFactory=abstractBeanFactory;
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	public Object getBean(String beanId) throws InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException, ClassNotFoundException {
		Object object=getBeanIdObject().get(beanId);
		if(null!=object)
			return object;
		Class clazz=getBeanIdClass().get(beanId);
		if(null==clazz)
			return null;
		object=clazz.newInstance();
		Field[] fields=clazz.getDeclaredFields();
		for (Field field : fields) {
			String methodName="set"+StringUtil.bigCaseFirstChar(field.getName());
			Value value=(Value) field.getAnnotation(Value.class);
			Method method=clazz.getMethod(methodName, String.class);
			if(value!=null){
				//TODO 这里要添加多种类型的支持
				String propertyValue=value.value();
				method.invoke(object, propertyValue);
			}
			Resource resource=(Resource) clazz.getAnnotation(Resource.class);
			if(null!=resource){
				String propertyBeanId=resource.name();
				if(StringUtils.isEmpty(propertyBeanId)){
					//如果name是空的就默认类的首字母小写，
					propertyBeanId=StringUtil.smallCaseFirstChar(field.getType().getSimpleName());
				}
				Object propertyObj=parentFactory.getBean(propertyBeanId);
				method.invoke(object, propertyObj);
			}
		}
		addObject(beanId, object);
		return object;
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	public void load() throws IOException, SAXException, ClassNotFoundException {
		List<Scan> scans=getBeans().getScans();
		for (int i = 0; i < scans.size(); i++) {
			String packageName = scans.get(i).getPackageName();
			String rootPath = BeanUtil.class.getResource("/").getPath();
			rootPath = URLDecoder.decode(rootPath, "utf-8");
			File file = new File(rootPath + File.separator
					+ packageName.replace(".", File.separator));
			String[] fileNames = file.list();
			if(null!=fileNames){
				for (String fileName : fileNames) {
					String className = fileName.substring(0, fileName.length()
							- ".class".length());
					String fullClassName = packageName + "." + className;
					Class clazz = Class.forName(fullClassName);
					Component component = (Component) clazz
							.getAnnotation(Component.class);
					if (null != component) {
						String beanId = component.value();
						if (StringUtils.isEmpty(beanId)) {
							beanId = StringUtil.smallCaseFirstChar(className);
						}
						addClass(beanId, clazz);
					}
				}
			}
		}
	}
	
	/**
	 * 获得扫描包下的所有文件名
	 * @param scans
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	@SuppressWarnings("unused")
	private List<String> getAnnotationClassNames(Scan scan)
			throws UnsupportedEncodingException {
		List<String> fileNames = new ArrayList<String>();
		String packageName = scan.getPackageName();
		String rootPath = URLDecoder.decode(AnnotationBeanFactory.class
				.getResource("/").getPath(), "utf-8");
		File file = new File(rootPath + File.separator
				+ packageName.replace(".", File.separator));
		CollectionUtils.addAll(fileNames, file.list());
		return fileNames;
	}

	@Override
	public void addClass(String beanId, Class clazz) {
		parentFactory.addClass(beanId, clazz);
	}

	@Override
	public Beans getBeans() {
		return parentFactory.getBeans();
	}

	@Override
	public Map<String, Class> getBeanIdClass() {
		return parentFactory.getBeanIdClass();
	}

	@Override
	public Map<String, Object> getBeanIdObject() {
		return parentFactory.getBeanIdObject();
	}
	
}
